package com.woniu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.client.TUserClient;
import com.woniu.dto.GoodsOrderDto;
import com.woniu.dto.OrderDetailsDto;
import com.woniu.dto.TUserDto;
import com.woniu.dto.UserAddressDto;
import com.woniu.execption.goods.GoodsException;
import com.woniu.execption.goods.GoodsExceptionCode;
import com.woniu.mapper.GoodsOrderMapper;
import com.woniu.model.Goods;
import com.woniu.model.GoodsOrder;
import com.woniu.model.OrderDetails;
import com.woniu.model.Result;
import com.woniu.params.DownOrderParam;
import com.woniu.service.GoodsOrderService;
import com.woniu.service.GoodsService;
import com.woniu.service.OrderDetailsService;
import com.woniu.utils.RedisKeyUtil;
import com.woniu.utils.RedisUtil;
import com.woniu.utils.StateData;
import io.seata.spring.annotation.GlobalTransactional;
import org.checkerframework.checker.units.qual.A;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 吴彦祖
 * @since 2024年05月25日
 */
@Service
public class GoodsOrderServiceImpl extends ServiceImpl<GoodsOrderMapper, GoodsOrder> implements GoodsOrderService {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private TUserClient tUserClient;

    @Autowired
    private OrderDetailsService orderDetailsService;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    //private List<OrderDetailsDto> dtos;

    /**
     * 用户下单接口
     * @param param
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Throwable.class)
    public GoodsOrderDto downOrder(DownOrderParam param) throws Exception {
        //判断用户是否实名
        Result<TUserDto> result1 = tUserClient.userById((long) param.getUserId());
        if (result1.getCode()!=200) {
            throw new Exception("调用服务失败");
        }
        if (result1.getData()==null) {
            throw new Exception("不存在的用户");
        }
        if (result1.getData().getRealNameState()!=1) {
            throw new Exception("请先实名认证");
        }
        //用户传入的商品id
        List<Integer> listIds = param.getGoodsIds();
        Set<Integer> setIds = listIds.stream().collect(Collectors.toSet());
        if (listIds.size()!=setIds.size()) throw new GoodsException(GoodsExceptionCode.SHOPPING_CAR_IS_NULL);
        //判断传入的商品id是否和redis的购物车数据是否匹配
        if (!redisUtil.exist(RedisKeyUtil.userShopping(param.getUserId())))  throw new GoodsException(GoodsExceptionCode.SHOPPING_CAR_IS_NULL);
        Set<Integer> ids = redisUtil.zrange(RedisKeyUtil.userShopping(param.getUserId()))
                .stream().map(Integer::valueOf)
                .collect(Collectors.toSet());
        //不包含
        if (!ids.containsAll(setIds)) {
            throw  new GoodsException(GoodsExceptionCode.SHOPPING_CAR_IS_NULL);
        }
        //查看是否有默认地址
        Result<UserAddressDto> defaultAddress = tUserClient.addressByUserId(param.getUserId());

        //判断地址合法性
        Result<UserAddressDto> result = tUserClient.addressById(Long.valueOf(param.getAddressId()));
        if (result.getCode()!=200) {
            throw new Exception(result.getMessage());
        }
        if (result.getData()==null&&defaultAddress.getData()==null) throw new Exception("还未填写地址信息,也为设置默认地址信息");
        if (result.getData().getUserId().intValue()!=param.getUserId()) throw new Exception("不是你的地址信息");
        if (result.getData().getState().longValue()!= StateData.ADDRESS_STATE_NORMAL) {
            throw new Exception("地址状态异常");
        }

        //创建多个单锁
        RLock[] lockArray = new RLock[param.getGoodsIds().size()];

        int index = 0;
        for (Integer bookId : param.getGoodsIds()) {
            RLock l = redissonClient.getFairLock(RedisKeyUtil.bookIdLock(bookId + ""));
            lockArray[index++] = l;
        }
        System.out.println("锁数组");
        System.out.println(lockArray);
        //使用数组创建多资源锁
        RLock lock = redissonClient.getMultiLock(lockArray);
        try {
            GoodsOrderDto dto = new GoodsOrderDto();
            String orderNum = new Snowflake(1, 1).nextIdStr();
            GoodsOrder goodsOrder = new GoodsOrder();
            goodsOrder.setOrderNum(orderNum);
            goodsOrder.setUserId(new Long(param.getUserId()));
            goodsOrder.setCreateTime(LocalDateTime.now().toString());
            //用户是否使用默认地址的情况
            if (param.getAddressId().longValue()!=0){
                goodsOrder.setName(result.getData().getName());
                goodsOrder.setPhone(result.getData().getPhone());
                goodsOrder.setAddress(result.getData().getUserAddress());
            }else {
                goodsOrder.setName(defaultAddress.getData().getName());
                goodsOrder.setPhone(defaultAddress.getData().getPhone());
                goodsOrder.setAddress(defaultAddress.getData().getUserAddress());
            }
            goodsOrder.setState(Long.valueOf(StateData.ORDER_STATE_NOT_PAY));
            BigDecimal sumPrice = new BigDecimal(0);
            List<OrderDetailsDto> dtos = new ArrayList<>();

            for (Integer goodsId : param.getGoodsIds()) {


                OrderDetails orderDetails = new OrderDetails();
                //取出redis的数据 存入数据库
                Map<Object, Object> map = redisUtil.hgetall(RedisKeyUtil.shoppingInfo(param.getUserId(), goodsId));
                orderDetails.setGoodsCont(Long.parseLong(map.get("number").toString()));
                orderDetails.setGoodsId(Long.parseLong(map.get("goodsId").toString()));
                orderDetails.setGoodsName(map.get("name").toString());
                orderDetails.setGoodsImage(map.get("img").toString());
                //单价
                BigDecimal price = new BigDecimal(map.get("price").toString());
                orderDetails.setGoodsPrice(price);
                orderDetails.setUserId(new Long(param.getUserId()));
                orderDetails.setOrderNum(orderNum);
                orderDetailsService.save(orderDetails);
                //计算订单的总价格
                BigDecimal number = new BigDecimal(map.get("number").toString());
                sumPrice =  sumPrice.add(price.multiply(number));

                //System.out.println("--------------------------------");
                //System.out.println(orderDetails.getGoodsName());
                OrderDetailsDto detailsDto = BeanUtil.toBean(orderDetails, OrderDetailsDto.class);
                dtos.add(detailsDto);
                //dto.getOrderDetails().add(detailsDto);
                //System.out.println(detailsDto.getGoodsName());

                //修改该商品的冻结量 和库存
                Goods goods = goodsService.getById(goodsId);
                //商品库存不足
                if (goods.getNumber()<orderDetails.getGoodsCont()) throw new GoodsException(GoodsExceptionCode.GOOD_NUMBER_INSUFFICIENT);
                if (goods==null) {
                    throw new GoodsException(GoodsExceptionCode.GOODS_NOT_EXITS);
                }
                if (goods.getState().longValue()!= StateData.GOODS_STATE_NORMAL) {
                    throw new GoodsException(GoodsExceptionCode.GOODS_STATE_ERROR);
                }

                goods.setFreeze(goods.getFreeze()+Integer.parseInt(map.get("number").toString()));

                goods.setNumber(goods.getNumber()-Integer.parseInt(map.get("number").toString()));
                goodsService.updateById(goods);
                //清空本次下单后的购物车数据
                //删除sored set 列表的id
                redisUtil.zrem(RedisKeyUtil.userShopping(param.getUserId()),goodsId+"");
                //删除商品的详细数据
                redisUtil.del(RedisKeyUtil.shoppingInfo(param.getUserId(),goodsId));
            }
            goodsOrder.setPrice(sumPrice);
            save(goodsOrder);

            GoodsOrderDto orderDto = BeanUtil.toBean(goodsOrder, GoodsOrderDto.class);
            orderDto.getOrderDetails().addAll(dtos);
            //将订单编号发送到延时队列中
            rabbitTemplate.convertAndSend("ordernum_delay_queue",orderNum);

            return orderDto;
        }finally {
            lock.unlock();
        }


    }

    /**
     * 用户支付积分商品(使用积分支付)
     * @param orderNum 订单号
     * @param userId 用户id
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Throwable.class)
    public GoodsOrder pay(String orderNum, int userId) throws Exception {
        //查看订单合法性
        GoodsOrder goodsOrder = getOne(new QueryWrapper<GoodsOrder>().eq("order_num", orderNum));
        if (goodsOrder==null) {
            throw new Exception("订单不存在");
        }
        if (goodsOrder.getUserId().longValue()!=userId) {
            throw new Exception("不是你的订单");
        }
        //订单是否是未支付状态
        if (goodsOrder.getState().longValue()!= StateData.ORDER_STATE_NOT_PAY) {
            throw new Exception("订单状态异常");
        }
        //判断时间是否在15分钟内
        String createTimeStr = goodsOrder.getCreateTime();
        long createTime = DateUtil.parse(createTimeStr, "yyyy-MM-dd HH:mm:ss").getTime();
        long nowTime = System.currentTimeMillis();
        if (nowTime-createTime>900000) {
            throw new Exception("订单超时");
        }
        //用户积分是否足够
        Result<TUserDto> result = tUserClient.userById(Long.valueOf(userId));
        if (result.getCode()!=200) throw  new Exception("调用服务失败");
        if (result.getData()==null) {
            throw new Exception("不存在的用户");
        }
        TUserDto resultData = result.getData();
        if (resultData.getScore().compareTo(goodsOrder.getPrice())==-1) {
            throw new Exception("积分不足");
        }
        //修改冻结量 成功的情况
        //修改订单状态(已支付)
        goodsOrder.setState(Long.valueOf(StateData.ORDER_STATE_PAYED));
        goodsOrder.setPayTime(LocalDateTime.now().toString());
        updateById(goodsOrder);

        List<OrderDetails> orderDetails = orderDetailsService.list(new QueryWrapper<OrderDetails>().eq("order_num", orderNum));
        List<Long> goodIds = orderDetails.stream().map(OrderDetails::getGoodsId).collect(Collectors.toList());
        List<Goods> goods = goodsService.listByIds(goodIds);
        for (Goods good : goods) {
            for (OrderDetails orderDetail : orderDetails) {
                if (good.getId().longValue()==orderDetail.getGoodsId().longValue()) {
                    good.setFreeze((int) (good.getFreeze()-orderDetail.getGoodsCont()));
                }
            }
        }
        goodsService.updateBatchById(goods);
        //修改用户积分
        Result<TUserDto> result1 = tUserClient.userById((long) userId);
        if (result1.getCode()!=200) {
            throw new Exception("调用服务异常");
        }
        tUserClient.modifyScore(userId,goodsOrder.getPrice().negate());
        //补偿机制(mq)

        return goodsOrder;
    }
}
